/****************************************************************************
**  Tite Interactive Text Engine (TiTE)
**  Copyright (C) 2010  Eisoft Group
**
**  This file is part of TiTE.
**
**  TiTE is free software: you can redistribute it and/or modify
**  it under the terms of the GNU General Public License as published by
**  the Free Software Foundation, either version 3 of the License, or
**  (at your option) any later version.
**
**  TiTE is distributed in the hope that it will be useful,
**  but WITHOUT ANY WARRANTY; without even the implied warranty of
**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
**  GNU General Public License for more details.
**
**  You should have received a copy of the GNU General Public License
**  along with TiTE.  If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/

/*!
 * \file singleton_policies.hpp
 *
 * \date 01/10/2011
 */

#ifndef TITE_CORE_SINGLETON_POLICIES_HPP
#define TITE_CORE_SINGLETON_POLICIES_HPP

#include <boost/thread/thread.hpp>
#include <cstdlib>
#include <stdexcept>

#include <tite/core/non_copyable.hpp>
#include <tite/core/safe_delete.hpp>
#include <tite/core/singleton/detail/singleton_types.hpp>
#include <tite/core/singleton/SingletonLifetimeManager.hpp>

/*!
 * \namespace tite
 *
 * \brief The TiTE namespace.
 */
namespace tite
{
    /*!
     * \namespace core
     *
     * \brief The TiTE core namespace.
     */
    namespace core
    {
        /*!
         * \namespace singleton_policies
         *
         * \brief Contains all policies for the singleton utility class.
         */
        namespace singleton_policies
        {
            /*!
             * \defgroup allocation Allocation policies.
             */
            /*@{*/
            /*!
             * \class default_dynamic_allocator
             *
             * \brief Defines a simple allocation (using new) policy for singleton.
             *
             * \author Jason Omahen
             * \version 0.02, 12/18/2010
             */
            template<typename T, 
                     template <typename> class ThreadingPolicy
            >
            class default_dynamic_allocator : private non_copyable
            {
            public:
                typedef typename ThreadingPolicy<T>::instance_ptr_t instance_ptr_t;

                static instance_ptr_t Create(void);
                static void Destroy(instance_ptr_t * _ppT);
            };

            /*!
             * \brief Allocates memory for a T using the default constructor.
             *
             * \return New T
             */
            template<typename T, 
                     template <typename> class ThreadingPolicy
            >
            typename default_dynamic_allocator<T, ThreadingPolicy>::instance_ptr_t default_dynamic_allocator<T, ThreadingPolicy>::Create(void)
            {
                return new T();
            }

            /*!
             * \brief Frees allocated memory for T using delete.
             *
             * \param _ppT Instance of T to free.
             */
            template<typename T, 
                     template <typename> class ThreadingPolicy
            >
            void default_dynamic_allocator<T, ThreadingPolicy>::Destroy(typename default_dynamic_allocator<T, ThreadingPolicy>::instance_ptr_t * _ppT)
            {
                safe_delete(_ppT);
            }
            /*@}*/

            /*!
             * \defgroup lifetime Lifetime policies.
             */
            /*@{*/
            /*!
             * \class cstd_lib_lifetime
             *
             * \brief Defines a simple lifetime policy for singleton. This policy uses
             *        general C++ rules.
             *
             * \author Jason Omahen
             * \version 0.02, 12/18/2010
             */
            template<typename T>
            class cstd_lib_lifetime : private non_copyable
            {
            public:
                template<priority_levels::PriorityLevel>
                    static void RegisterDeleter(c_deleter_func_t pCleanupFn);       
                static void DeadReferenceDetected(void);
            };

            /*!
             * \brief Registers the specified cleanup function with atexit().
             *
             * \param pCleanupFn Function that performs required cleanup.
             */
            template<typename T>
                template<priority_levels::PriorityLevel>
                void cstd_lib_lifetime<T>::RegisterDeleter(c_deleter_func_t pCleanupFn)
                {
                    ::std::atexit(pCleanupFn);
                }

            /*!
             * \brief Called when a dead reference is detected.
             *        Throws an exception of a dead reference has been detected.
             */
            template<typename T>
            void cstd_lib_lifetime<T>::DeadReferenceDetected(void)
            {
                // Output to debug log
                throw ::std::logic_error("[singleton] Dead reference found!");
            }
        
            /*!
             * \class managed_lifetime
             *
             * \brief Defines a simple lifetime policy for singleton. This policy uses
             *        general C++ rules by default, but allows for finer control on
             *        object destruction with priorities.
             *
             * \author Jason Omahen
             * \version 0.02, 12/18/2010
             */
            template<typename T>
            class managed_lifetime : private non_copyable
            {
            public:
                template<priority_levels::PriorityLevel Priority>
                    static deleter_func_t *const RegisterDeleter(const deleter_func_t & cleanupFn);          
                static void DeadReferenceDetected(void);
            };

            /*!
             * \brief Registers the specified cleanup function with SingletonLifetimeManager.
             *
             * \param cleanupFn Function that performs required cleanup.
             */
            template<typename T>
                template<priority_levels::PriorityLevel Priority>
                deleter_func_t *const managed_lifetime<T>::RegisterDeleter(const deleter_func_t & cleanupFn)  
                {
                    return SingletonLifetimeManager::GetInstance()->registerDeleter(cleanupFn, Priority);
                }

            /*!
             * \brief Called when a dead reference is detected.
             *        Throws an exception of a dead reference has been detected.
             */
            template<typename T>
            void managed_lifetime<T>::DeadReferenceDetected(void)
            {
                // Output to debug log
                throw ::std::logic_error("[singleton] Dead reference found!");
            }
            /*@}*/

            /*!
             * \defgroup threading Threading policies.
             */
            /*@{*/
            /*!
             * \class single_threaded
             *
             * \brief Defines a single-threaded threading policy for singleton.
             *
             * \author Jason Omahen
             * \version 0.02, 12/18/2010
             */
            template<typename T>
            class single_threaded : private non_copyable
            {
            public:
                typedef T* instance_ptr_t;

                /*!
                 * \class ThreadLock singleton_policy.hpp
                 *
                 * \brief Dummy lock class for compatibility.
                 */
                class ScopedThreadLock : private non_copyable
                {
                public:
                    template <typename MutexType>
                    ScopedThreadLock(const MutexType &) {}
                };

                /*!
                 * \class Mutex singleton_policy.hpp
                 *
                 * \brief Dummy mutex class for compatibility.
                 */
                class Mutex : private non_copyable {};

            private:
                // Prevent object creation
                single_threaded(void);
                ~single_threaded(void);
            };

            /*!
             * \class multi_threaded
             *
             * \brief Defines a multi-threaded threading policy for singleton.
             *
             * \author Jason Omahen
             * \version 0.02, 12/18/2010
             */
            template<typename T>
            class multi_threaded : private non_copyable
            {
            public:
                typedef T* instance_ptr_t;
                typedef boost::mutex::scoped_lock ScopedThreadLock;
                typedef boost::mutex Mutex;

            private:
                // Prevent object creation
                multi_threaded(void);
                ~multi_threaded(void);
            };
            /*@}*/
        }// End of singleton_policies namespace
    }// End of core namespace
}// End of tite namespace

#endif /* TITE_CORE_SINGLETON_POLICIES_HPP */